Java™ Native Interface (JNI) is a standard programming interface for writing Java native methods and embedding the Java™ virtual machine into native applications. The JNI allows Java code that runs within a Java Virtual Machine (JVM) to operate with applications and libraries written in other languages, such as C, C++, and assembly. JNI also facilitates native code access to Java VM features by calling JNI functions. Thus JNI serves as the glue between Java and Native application and is a powerful feature, which will allow programmers to take advantage of the Java Platform as well as utilize code written in other languages.
Native language implementation may be preferred in the following scenarios: support for certain platform-dependent features for which Java does not provide an interface; interface to legacy code or implementation already available; situations that require loading the native library in the same process; substitution of Java™ code with lower level code gives a better performance for any time-critical application. Programmers mostly use JNI when an application needs to incorporate certain native level implementation.
While the Java™ programming language is type-safe and secure, native languages such as C or C++ are not. As a result, extra care is needed when writing applications using the JNI. A misbehaving native method can corrupt the entire application. The JNI does very little management; it mostly provides a vehicle for the code. For a programmer, Java™ Native Interface (JNI) methods are difficult to understand and implement.
There are several things that a JNI programmer must take care to produce correct JNI code. The programmer should guard the code against the common pitfalls and traps, which can affect performance and cause runtime failures. The following are the typical traps and pitfalls associated with JNI programming:
1. Error Checking—The most common mistake when writing native methods is forgetting to check whether an error condition has occurred. Unlike the Java™ programming language, native languages do not offer standard exception mechanisms. The JNI does not rely on any particular native exception mechanism (such as C++ exceptions). As a result, programmers are required to perform explicit checks after every JNI function call that could possibly raise an exception.2. Using Java™ Objects—Java™ objects if used as they are in the native side may produce undesirable results and also can crash the Java Virtual Machine3. Local and Global References—There are certain considerations required when a programmer uses local or global references to make good JNI code.4. Freeing Native Resources—Failure to call Release* methods after use of resource acquired through Get* JNI methods, results in a memory leak which could ultimately lead to memory exhaustion.5. Explicit Return—A pending exception thrown through the JNI does not automatically change control flow in native code. Instead, the programmer needs to issue an explicit return statement in order to skip the remaining statements in the C function.6. String Manipulation—Differences in string representation when switching between UTF-8 and Unicode strings.7. Concurrent Programming—There are certain constraints that one must keep in mind when writing native methods that are to run in a multithreaded environment. For instance, a JNIEnv pointer is only valid in the thread associated with it. The programmer must not pass this pointer from one thread to another or cache and use it in multiple threads.
Java Virtual Machine (JVM) implementations provide certain command-line options like Xcheck:jni and Xcheck:nabounds. These options instruct the virtual machine to detect and report many, albeit not all, cases of native code passing illegal arguments to JNI functions. The tool, however, warns against invalid arguments passed to the JNI functions at compile time and at runtime. The runtime checking slows down performance drastically. The implementation of the JNI specification and the JNI command-line options differ from vendor to vendor. For instance, the implementation of Java Objects, local and global references may differ between vendors. No tools are currently available for the developer community, which perform these checks based on the JVM and the JNI implementation.